package com.shxzz.shortlink.admin.common.biz.user;

import cn.hutool.core.text.CharSequenceUtil;
import com.alibaba.fastjson2.JSON;
import com.shxzz.shortlink.admin.common.convention.result.Result;
import com.shxzz.shortlink.admin.common.convention.result.Results;
import com.shxzz.shortlink.admin.common.enums.UserErrorCode;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static com.shxzz.shortlink.admin.common.constant.RedisCacheConstant.USER_LOGIN_INFO_KEY;

/**
 * @author shxzz
 * @create 2023-12-12-21:13
 * @description 用户登录请求拦截器，验证用户登录状态
 */
@Component
@RequiredArgsConstructor
public class LoginAuthInterceptor implements HandlerInterceptor {

    private final StringRedisTemplate stringRedisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

        String username = request.getHeader("username");
        String token = request.getHeader("token");

        if(CharSequenceUtil.hasBlank(username, token)) {
            responseError(response, UserErrorCode.USER_TOKEN_FAIL.getCode(), UserErrorCode.USER_TOKEN_FAIL.getMsg());
            return false;
        }

        UserInfoDTO userInfo = Optional
                .ofNullable(stringRedisTemplate.opsForHash().get(USER_LOGIN_INFO_KEY + username, token))
                .map(s -> JSON.parseObject(s.toString(), UserInfoDTO.class))
                .orElse(null);

        if(userInfo == null) {
            responseError(response, UserErrorCode.USER_TOKEN_FAIL.getCode(), UserErrorCode.USER_TOKEN_FAIL.getMsg());
            return false;
        }
        // 刷新登陆状态
        Boolean result = stringRedisTemplate.expire(USER_LOGIN_INFO_KEY + username, 30L, TimeUnit.MINUTES);
        if(Boolean.FALSE.equals(result)) {
            responseError(response, UserErrorCode.USER_LOGIN_EXPIRED.getCode(), UserErrorCode.USER_LOGIN_EXPIRED.getMsg());
            return false;
        }
        UserContext.setUser(userInfo);

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) {
        UserContext.removeUser();
    }

    private void responseError(HttpServletResponse response, String errorCode, String errorMsg) {
        Result<Void> failure = Results.failure(errorCode, errorMsg);

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");

        try (PrintWriter writer = response.getWriter();){
            writer.write(JSON.toJSONString(failure));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
